
""" 
Copyright 2009 Texas A&M University
 
Licensed under the Apache License, Version 2.0 (the "License"); you may not use 
this file except in compliance with the License. You may obtain a copy of the 
License at

http://www.apache.org/licenses/LICENSE-2.0
  
Unless required by applicable law or agreed to in writing, software distributed 
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
CONDITIONS OF ANY KIND, either express or implied. See the License for the 
specific language governing permissions and limitations under the License.
"""

from copy import copy
import re
from urllib import quote, quote_plus, urlencode
from logging import getLogger

import zope.interface
from zope.component import queryUtility,getMultiAdapter

from Acquisition import aq_inner,aq_parent

from plone.app.layout.globals.interfaces import IViewView

from plone.memoize.view import memoize, memoize_contextless

from meercat.ui.plone import labeledFilterQueryFieldExpression
from meercat.ui.plone.browser.content.base import BaseView
from meercat.ui.plone.browser.interfaces import *
from meercat.ui.plone.connection import unicodeParameterEncoding
from meercat.ui.plone.interfaces import IMeercatConnectionManager



log = getLogger('meercat.ui.plone')

__all__ = ['SearchView',
           'BrowseView',
           'TiledSearchView',
           'TiledBrowseView']

class BaseQueryView(BaseView):
    zope.interface.implements(IViewView, IMeercatSearchView)
    
    solrResponse = None
    facetFields = None
    page = None
    paginator = None
    
    def __call__(self, *args, **kwargs):
        params = self.getQueryParameters()
        
        if params:
            self.solrResponse = self.query(**params)
        
        if self.solrResponse:
            self.paginator = getattr(self.solrResponse,'paginator',None)
            if self.paginator:
                self.page = self.paginator.page(int(self.request.get('page',1)))
            else:
                log.error('No paginator on results')
        else:
            log.debug('No response returned')
        
        return super(BaseQueryView, self).__call__(*args, **kwargs)
    
    @property
    @memoize
    def site_url(self):
        return getMultiAdapter((self.context, self.request),
                               name=u'plone_portal_state').portal_url()
    
    def getResourceUrl(self, identifier):
        return '%s/@@meercat-resource/?id=%s' % (self.context.absolute_url(),
                                                 identifier)
    
    def getQueryParameters(self):
        log.debug('%s.getQueryParameters()' % (str(self),))
        
        params = self.context.getQueryParameters()
        params.setdefault('rows',self.request.get('page_size',25))
        params['q'] = self.request.get('q',None)
        
        if self.context.allowSortSelection and self.request.get('sort',False):
            params['sort'] = self.request.get('sort')
        
        fq = self.request.get('fq',[])
        
        if not isinstance(fq,list):
            fq = [fq]
        
        if self.request.get('qf',None) and params.get('qt','') != 'standard':
            params['qf'] = self.request.get('qf')
        
        if len(fq) > 0:
            params.setdefault('fq',[])
            
            for f in fq:
                m = labeledFilterQueryFieldExpression.match(f)
                if m:
                    f = '%(field)s:%(value)s' % (m.groupdict())
                
                params['fq'].append(f)
        
        return params
    
    @property
    @memoize
    def absolute_url(self):
        return self.request.URL
    
    @property
    @memoize
    def full_url(self):
        return "%s?%s" % (self.request.URL,urlencode(self.request.form))
    
    def getUrlWithParams(self, remove=[], replace=True, **params):
        """ Get a url for the current search with some parameters removed and/or
        replaced.
        
        remove: a list of parameters to remove. If a given list element is a 
        tuple, then the first element in the tuple is the key and the second
        is the value to remove. This only applies for multi-valued parameters.
        """
        p = self.request.form.copy()
        
        if replace:
            p.update(params)
        else:
            for k,v in params.iteritems():
                if not isinstance(v,list):
                    v = [v]
                
                if not k in p:
                    p[k] = []
                elif not isinstance(p[k],list):
                    p[k] = [p[k]]
                else:
                    p[k] = copy(p[k])
                p[k].extend(v)
        
        for r in remove:
            try:
                key,value = r
            except:
                key = r
                value = None
                
            if key in p:
                if isinstance(p[key],list) and value:
                    p[key] = copy(p[key])
                    p[key].remove(value)
                else:
                    del p[key]
        
        return u'%s?%s' % (self.absolute_url,
                           urlencode(unicodeParameterEncoding(p),True))
    
    def getPaginator(self):
        return self.paginator
    
    def hasPaginator(self):
        return self.getPaginator() is not None
    
    def getCurrentPage(self):
        return self.page
    
    def hasCurrentPage(self):
        return self.getCurrentPage() is not None
    
    def hasResponse(self):
        return self.solrResponse is not None
    
    @memoize
    def getResults(self):
        if self.hasResponse() and self.page:
            return self.page.object_list
    
    def hasResults(self):
        return bool(self.getResults())

    def getStartNumber(self):
        if not self.page:
            return 0
        
        return self.page.start_index() + 1
    
    def getEndNumber(self):
        if not self.page:
            return 0
        
        return self.page.end_index() + 1

class BaseBrowseView(BaseQueryView):
    zope.interface.implements(IBrowseableView)
    
    def getQueryParameters(self):
        params = super(BaseBrowseView, self).getQueryParameters()
        
        if not 'q' in params or not params['q']:
            params['q'] = '%s:[* TO *]' % (self.manager.getIdentifierField(),)
        
        return params

class BaseSearchView(BaseQueryView):
    zope.interface.implements(ISearchableView)
    
    def getQueryParameters(self):
        params = super(BaseSearchView, self).getQueryParameters()
        if not 'q' in params or not params['q']:
            return None
        
        return params

class SearchView(BaseSearchView):
    zope.interface.implements(IListView)

class BrowseView(BaseBrowseView):
    zope.interface.implements(IListView)

class TiledSearchView(BaseSearchView):
    zope.interface.implements(ITiledView)

class TiledBrowseView(BaseBrowseView):
    zope.interface.implements(ITiledView)
